<?php


namespace app\api\controller;


use app\api\model\SystemMenu;
use app\common\controller\Api;
use app\common\controller\OperationLog;
use think\Db;
use think\db\exception\DataNotFoundException as DataNotFoundExceptionAlias;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\DbException;
use think\Request;

/**
 * Class Menu
 * @package app\api\controller
 */
class Menu extends \app\common\controller\Api
{
    /**
     * @var bool 无需登录的方法
     */
    protected $noNeedLogin = [];

    /**
     * @var bool 无需鉴权的方法
     */
    protected $noNeedAuth = [];

    /**
     * @var array 无需token的方法
     */
    protected $noNeedToken = [];

    /**
     * 获取菜单列表
     */
    public function get_menus()
    {
        // 定义日志参数
        $options = array(
            'title' => '获取菜单目录和路由配置信息',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        try {
            $menuInfo['menu_data'] = $this->get_menu_list();
            $menuInfo['router_data'] = Db::name('system_menu')
                ->order('sort', 'desc')
                ->field('id,pid,name,component,path,icon')
                ->where('component', '<>', '')
                ->select();
            OperationLog::OperSuccess([], $options, 'R', $menuInfo);
            $this->success('success', ['code' => 200, 'data' => $menuInfo]);
        } catch (DataNotFoundExcesuccessption $e) {
            OperationLog::OperError([], $options, 'R', $e->getMessage(), $e->getMessage());
            $this->error('error', $e->getMessage(), 202);
        } catch (ModelNotFoundException $e) {
            OperationLog::OperError([], $options, 'R', $e->getMessage(), $e->getMessage());
            $this->error('error',  $e->getMessage(), 202);
        } catch (DbException $e) {
            OperationLog::OperError([], $options, 'R', $e->getMessage(), $e->getMessage());
            $this->error('error',  $e->getMessage(), 202);
        }
    }

    /**
     * 获取菜单列表
     * @return array
     * @throws DataNotFoundExceptionAlias
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function get_menu_list(): array
    {
        $where = [];
        $where['type'] = ['in', ['M', 'C']];
        $where['is_disable'] = ['=', 0];
        $where['is_show'] = ['=', 1];
        $menuList = SystemMenu::where($where)
            ->order('sort', 'desc')
            ->field(['id,pid,name,component,path,icon'])
            ->select();
        $menuList = Api::build_menu_child(0, $menuList);
        return $menuList;
    }

    /**
     * 获取菜单列表
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws DataNotFoundExceptionAlias
     */
    public function lists()
    {
        // 定义日志参数
        $options = array(
            'title' => '获取菜单目录和路由配置信息',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        $where = [];
        $where['type'] = ['in', ['M', 'C', 'A']];
        $menuList = SystemMenu::where($where)
            ->order('sort', 'desc')
            ->field(['id as value,pid as pid,name as title,type,icon,perms,is_disable,sort,update_time'])
            ->select();
        OperationLog::OperSuccess([], $options, 'R', $menuList);
        $this->success('success', ['code' => 200, 'data' => $menuList]);
    }

    /**
     * 菜单添加方法
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws DataNotFoundExceptionAlias
     */
    public function add()
    {
        // 定义日志参数
        $options = array(
            'title' => '添加菜单',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
        );
        $param = Request::instance()->post() ?? [];
        $validRes = $this->validate($param, 'SystemMenu.add');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'C', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        $parentMenu = SystemMenu::get(['id' => $param['pid']]);
        if (empty($parentMenu) && $param['pid'] === 0) {
            OperationLog::OperError($param, $options, 'C', '父级菜单不存在!');
            $this->error('error', ['code' => 201, 'data' => '父级菜单不存在!']);
        }
        $existMenu = SystemMenu::get(['path' => $param['path']]);
        if (!empty($existMenu) && !empty($param['path'])) {
            OperationLog::OperError($param, $options, 'C', '该路由已存在!');
            $this->error('error', ['code' => 201, 'data' => '路由已存在']);
        }
        Db::startTrans();
        try {
            $childMenu = new SystemMenu();
            $childMenu->save($param);
            Db::commit();
            OperationLog::OperSuccess($param, $options, 'C', '菜单添加成功');
            $this->success('success', ['code' => 200, 'data' => '操作成功']);
        } catch (Exception $e) {
            OperationLog::OperError($param, $options, 'C', $e->getMessage());
            $this->error('error',  $e->getMessage(), 202);
        }
    }

    /**
     * 菜单删除
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws DataNotFoundExceptionAlias
     */
    public function del()
    {
        // 定义日志参数
        $options = array(
            'title' => '删除菜单',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        // 接收参数
        $param = Request::instance()->param() ?? [];
        // 校验参数是否合法
        $validRes = $this->validate($param, 'SystemMenu.del');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'D', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        // 验证菜单的id是否存在,然后验证当前id有无子菜单,有提示不能删除
        $checkExistMenu = SystemMenu::get(['id' => $param['id']]);
        if (empty($checkExistMenu)) {
            OperationLog::OperError($param, $options, 'D', '菜单不存在!');
            $this->error('error', ['code' => 201, 'data' => '菜单不存在!']);
        } else {
            $checkExistChildMenu = SystemMenu::get(['pid' => $param['id']]);
            if (!empty($checkExistChildMenu)) {
                OperationLog::OperError($param, $options, 'D', '当前菜单存在子菜单,无法删除!');
                $this->error('error', ['code' => 201, 'data' => '当前菜单存在子菜单,无法删除!']);
            } else {
                Db::startTrans();
                try {
                    $checkExistMenu->delete(true);
                    Db::commit();
                    OperationLog::OperSuccess($param, $options, 'D', '操作成功!');
                    $this->success('success', ['code' => 200, 'data' => '操作成功!']);
                } catch (Exception $e) {
                    Db::rollback();
                    OperationLog::OperError($param, $options, 'D', $e->getMessage());
                    $this->error('error',  $e->getMessage(), 202);
                }
            }
        }
    }

    /**
     * 获取菜单详情
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws DataNotFoundExceptionAlias
     */
    public function detail()
    {
        // 定义日志参数
        $options = array(
            'title' => '查看菜单详情',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        // 接收参数
        $param = Request::instance()->param() ?? [];
        $validRes = $this->validate($param, 'SystemMenu.detail');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'R', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        $findRes = SystemMenu::get(['id' => $param['id']])->hidden(['update_time', 'create_time']);
        if (empty($findRes)) {
            OperationLog::OperError($param, $options, 'R', '暂未找到该菜单!');
            $this->error('error', ['code' => 201, 'data' => '暂未找到该菜单!']);
        }
        OperationLog::OperSuccess($param, $options, 'R', $findRes);
        $this->success('success', ['code' => 200, 'data' => $findRes]);
    }

    /**
     * 菜单修改方法
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws DataNotFoundExceptionAlias
     */
    public function edit()
    {
        // 定义日志参数
        $options = array(
            'title' => '修改菜单信息',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
        );
        $param = Request::instance()->post() ?? [];
        $validRes = $this->validate($param, 'SystemMenu.edit');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'U', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        if ($param['id'] === $param['pid']) {
            OperationLog::OperError($param, $options, 'U', '上级菜单不能选择自己!');
            $this->error('error', ['code' => 201, 'data' => '上级菜单不能选择自己!']);
        }
        $parentMenu = SystemMenu::get(['id' => $param['pid']]);
        if (empty($parentMenu) && $param['pid'] === 0) {
            OperationLog::OperError($param, $options, 'U', '父级菜单不存在!');
            $this->error('error', ['code' => 201, 'data' => '父级菜单不存在!']);
        }
        $existMenu = SystemMenu::get(['path' => $param['path']]);
        if (!empty($existMenu) && $existMenu['id'] != $param['id'] && !empty($param['path'])) {
            OperationLog::OperError($param, $options, 'U', '该路由已存在!');
            $this->error('error', ['code' => 201, 'data' => '路由已存在']);
        }
        $menu = SystemMenu::get(['id' => $param['id']]);
        if (empty($menu)) {
            OperationLog::OperError($param, $options, 'U', '菜单不存在!');
            $this->error('error', ['code' => 201, 'data' => '菜单不存在!']);
        }
        Db::startTrans();
        try {
            $menu->save($param, ['id' => $param['id']]);
            Db::commit();
            OperationLog::OperSuccess($param, $options, 'U', '菜单修改成功');
            $this->success('success', ['code' => 200, 'data' => '操作成功']);
        } catch (Exception $e) {
            OperationLog::OperError($param, $options, 'U', $e->getMessage());
            $this->error('error', $e->getMessage(), 202);
        }
    }
}